/**
 ******************************************************************************
 * @file    bl702_timer.c
 * @version V1.0
 * @date
 * @brief   This file is the standard driver c file
 ******************************************************************************
 * @attention
 *
 * <h2><center>&copy; COPYRIGHT(c) 2020 Bouffalo Lab</center></h2>
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *   1. Redistributions of source code must retain the above copyright notice,
 *      this list of conditions and the following disclaimer.
 *   2. Redistributions in binary form must reproduce the above copyright notice,
 *      this list of conditions and the following disclaimer in the documentation
 *      and/or other materials provided with the distribution.
 *   3. Neither the name of Bouffalo Lab nor the names of its contributors
 *      may be used to endorse or promote products derived from this software
 *      without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 ******************************************************************************
 */

#include "bl702_timer.h"

/** @addtogroup  BL702_Peripheral_Driver
 *  @{
 */

/** @addtogroup  TIMER
 *  @{
 */

/** @defgroup  TIMER_Private_Macros
 *  @{
 */
#define TIMER_MAX_MATCH 3

/*@} end of group TIMER_Private_Macros */

/** @defgroup  TIMER_Private_Types
 *  @{
 */

/*@} end of group TIMER_Private_Types */

/** @defgroup  TIMER_Private_Variables
 *  @{
 */
intCallback_Type *timerIntCbfArra[3][TIMER_INT_ALL] = {
    {NULL, NULL, NULL},
    {NULL, NULL, NULL},
    {NULL, NULL, NULL}
};

/*@} end of group TIMER_Private_Variables */

/** @defgroup  TIMER_Global_Variables
 *  @{
 */

/*@} end of group TIMER_Global_Variables */

/** @defgroup  TIMER_Private_Fun_Declaration
 *  @{
 */
#ifndef BFLB_USE_HAL_DRIVER
static void TIMER_IntHandler(IRQn_Type irqNo, TIMER_Chan_Type timerCh);
#endif

/*@} end of group TIMER_Private_Fun_Declaration */

/** @defgroup  TIMER_Private_Functions
 *  @{
 */

/****************************************************************************/ /**
                                                                                * @brief  TIMER interrupt common handler function
                                                                                *
                                                                                * @param  irqNo: Interrupt ID type
                                                                                * @param  timerCh: TIMER channel type
                                                                                *
                                                                                * @return None
                                                                                *
                                                                                *******************************************************************************/
#ifndef BFLB_USE_HAL_DRIVER
void TIMER_IntHandler(IRQn_Type irqNo, TIMER_Chan_Type timerCh) {
  uint32_t intId;
  uint32_t tmpVal;
  uint32_t tmpAddr;

  intId   = BL_RD_WORD(TIMER_BASE + TIMER_TMSR2_OFFSET + 4 * timerCh);
  tmpAddr = TIMER_BASE + TIMER_TICR2_OFFSET + 4 * timerCh;
  tmpVal  = BL_RD_WORD(tmpAddr);

  /* Comparator 0 match interrupt */
  if (BL_IS_REG_BIT_SET(intId, TIMER_TMSR_0)) {
    BL_WR_WORD(tmpAddr, BL_SET_REG_BIT(tmpVal, TIMER_TCLR_0));

    if (timerIntCbfArra[irqNo - TIMER_CH0_IRQn][TIMER_INT_COMP_0] != NULL) {
      /* Call the callback function */
      timerIntCbfArra[irqNo - TIMER_CH0_IRQn][TIMER_INT_COMP_0]();
    }
  }

  /* Comparator 1 match interrupt */
  if (BL_IS_REG_BIT_SET(intId, TIMER_TMSR_1)) {
    BL_WR_WORD(tmpAddr, BL_SET_REG_BIT(tmpVal, TIMER_TCLR_1));

    if (timerIntCbfArra[irqNo - TIMER_CH0_IRQn][TIMER_INT_COMP_1] != NULL) {
      /* Call the callback function */
      timerIntCbfArra[irqNo - TIMER_CH0_IRQn][TIMER_INT_COMP_1]();
    }
  }

  /* Comparator 2 match interrupt */
  if (BL_IS_REG_BIT_SET(intId, TIMER_TMSR_2)) {
    BL_WR_WORD(tmpAddr, BL_SET_REG_BIT(tmpVal, TIMER_TCLR_2));

    if (timerIntCbfArra[irqNo - TIMER_CH0_IRQn][TIMER_INT_COMP_2] != NULL) {
      /* Call the callback function */
      timerIntCbfArra[irqNo - TIMER_CH0_IRQn][TIMER_INT_COMP_2]();
    }
  }
}
#endif

/****************************************************************************/ /**
                                                                                * @brief  Get the specified channel and match comparator value
                                                                                *
                                                                                * @param  timerCh: TIMER channel type
                                                                                * @param  cmpNo: TIMER comparator ID type
                                                                                *
                                                                                * @return Match comapre register value
                                                                                *
                                                                                *******************************************************************************/
uint32_t TIMER_GetCompValue(TIMER_Chan_Type timerCh, TIMER_Comp_ID_Type cmpNo) {
  uint32_t tmpVal;

  /* Check the parameters */
  CHECK_PARAM(IS_TIMER_CHAN_TYPE(timerCh));
  CHECK_PARAM(IS_TIMER_COMP_ID_TYPE(cmpNo));

  tmpVal = BL_RD_WORD(TIMER_BASE + TIMER_TMR2_0_OFFSET + 4 * (TIMER_MAX_MATCH * timerCh + cmpNo));
  return tmpVal;
}

/****************************************************************************/ /**
                                                                                * @brief  TIMER set specified channel and comparator compare value
                                                                                *
                                                                                * @param  timerCh: TIMER channel type
                                                                                * @param  cmpNo: TIMER comparator ID type
                                                                                * @param  val: TIMER match comapre register value
                                                                                *
                                                                                * @return None
                                                                                *
                                                                                *******************************************************************************/
void TIMER_SetCompValue(TIMER_Chan_Type timerCh, TIMER_Comp_ID_Type cmpNo, uint32_t val) {
  /* Check the parameters */
  CHECK_PARAM(IS_TIMER_CHAN_TYPE(timerCh));
  CHECK_PARAM(IS_TIMER_COMP_ID_TYPE(cmpNo));

  BL_WR_WORD(TIMER_BASE + TIMER_TMR2_0_OFFSET + 4 * (TIMER_MAX_MATCH * timerCh + cmpNo), val);
}

/****************************************************************************/ /**
                                                                                * @brief  TIMER get the specified channel count value
                                                                                *
                                                                                * @param  timerCh: TIMER channel type
                                                                                *
                                                                                * @return TIMER count register value
                                                                                *
                                                                                *******************************************************************************/
uint32_t TIMER_GetCounterValue(TIMER_Chan_Type timerCh) {
  uint32_t tmpVal;
  uint32_t tmpAddr;

  /* Check the parameters */
  CHECK_PARAM(IS_TIMER_CHAN_TYPE(timerCh));

  /* TO avoid risk of reading, don't read TCVWR directly*/
  /* request for read*/
  tmpAddr = TIMER_BASE + TIMER_TCVWR2_OFFSET + 4 * timerCh;
  BL_WR_WORD(tmpAddr, 1);

  /* Need wait */
  tmpVal = BL_RD_WORD(tmpAddr);
  tmpVal = BL_RD_WORD(tmpAddr);
  tmpVal = BL_RD_WORD(tmpAddr);

  return tmpVal;
}

/****************************************************************************/ /**
                                                                                * @brief  TIMER get specified channel and comparator match status
                                                                                *
                                                                                * @param  timerCh: TIMER channel type
                                                                                * @param  cmpNo: TIMER comparator ID type
                                                                                *
                                                                                * @return SET or RESET
                                                                                *
                                                                                *******************************************************************************/
BL_Sts_Type TIMER_GetMatchStatus(TIMER_Chan_Type timerCh, TIMER_Comp_ID_Type cmpNo) {
  uint32_t    tmpVal;
  BL_Sts_Type bitStatus = RESET;

  /* Check the parameters */
  CHECK_PARAM(IS_TIMER_CHAN_TYPE(timerCh));
  CHECK_PARAM(IS_TIMER_COMP_ID_TYPE(cmpNo));

  tmpVal = BL_RD_WORD(TIMER_BASE + TIMER_TMSR2_OFFSET + 4 * timerCh);

  switch (cmpNo) {
  case TIMER_COMP_ID_0:
    bitStatus = BL_IS_REG_BIT_SET(tmpVal, TIMER_TMSR_0) ? SET : RESET;
    break;

  case TIMER_COMP_ID_1:
    bitStatus = BL_IS_REG_BIT_SET(tmpVal, TIMER_TMSR_1) ? SET : RESET;
    break;

  case TIMER_COMP_ID_2:
    bitStatus = BL_IS_REG_BIT_SET(tmpVal, TIMER_TMSR_2) ? SET : RESET;
    break;

  default:
    break;
  }

  return bitStatus;
}

/****************************************************************************/ /**
                                                                                * @brief  TIMER get specified channel preload value
                                                                                *
                                                                                * @param  timerCh: TIMER channel type
                                                                                *
                                                                                * @return Preload register value
                                                                                *
                                                                                *******************************************************************************/
uint32_t TIMER_GetPreloadValue(TIMER_Chan_Type timerCh) {
  /* Check the parameters */
  CHECK_PARAM(IS_TIMER_CHAN_TYPE(timerCh));

  return BL_RD_WORD(TIMER_BASE + TIMER_TPLVR2_OFFSET + 4 * timerCh);
}

/****************************************************************************/ /**
                                                                                * @brief  TIMER set preload register low 32bits value
                                                                                *
                                                                                * @param  timerCh: TIMER channel type
                                                                                * @param  val: Preload register low 32bits value
                                                                                *
                                                                                * @return None
                                                                                *
                                                                                *******************************************************************************/
void TIMER_SetPreloadValue(TIMER_Chan_Type timerCh, uint32_t val) {
  /* Check the parameters */
  CHECK_PARAM(IS_TIMER_CHAN_TYPE(timerCh));

  BL_WR_WORD(TIMER_BASE + TIMER_TPLVR2_OFFSET + 4 * timerCh, val);
}

/****************************************************************************/ /**
                                                                                * @brief  TIMER set preload trigger source,COMP0,COMP1,COMP2 or None
                                                                                *
                                                                                * @param  timerCh: TIMER channel type
                                                                                * @param  plSrc: TIMER preload source type
                                                                                *
                                                                                * @return None
                                                                                *
                                                                                *******************************************************************************/
void TIMER_SetPreloadTrigSrc(TIMER_Chan_Type timerCh, TIMER_PreLoad_Trig_Type plSrc) {
  /* Check the parameters */
  CHECK_PARAM(IS_TIMER_CHAN_TYPE(timerCh));
  CHECK_PARAM(IS_TIMER_PRELOAD_TRIG_TYPE(plSrc));

  BL_WR_WORD(TIMER_BASE + TIMER_TPLCR2_OFFSET + 4 * timerCh, plSrc);
}

/****************************************************************************/ /**
                                                                                * @brief  TIMER set count mode:preload or free run
                                                                                *
                                                                                * @param  timerCh: TIMER channel type
                                                                                * @param  countMode: TIMER count mode: TIMER_COUNT_PRELOAD or TIMER_COUNT_FREERUN
                                                                                *
                                                                                * @return None
                                                                                *
                                                                                *******************************************************************************/
void TIMER_SetCountMode(TIMER_Chan_Type timerCh, TIMER_CountMode_Type countMode) {
  uint32_t tmpval;

  /* Check the parameters */
  CHECK_PARAM(IS_TIMER_CHAN_TYPE(timerCh));
  CHECK_PARAM(IS_TIMER_COUNTMODE_TYPE(countMode));

  tmpval = BL_RD_WORD(TIMER_BASE + TIMER_TCMR_OFFSET);
  tmpval &= (~(1 << (timerCh + 1)));
  tmpval |= (countMode << (timerCh + 1));

  BL_WR_WORD(TIMER_BASE + TIMER_TCMR_OFFSET, tmpval);
}

/****************************************************************************/ /**
                                                                                * @brief  TIMER clear interrupt status
                                                                                *
                                                                                * @param  timerCh: TIMER channel type
                                                                                * @param  cmpNo: TIMER macth comparator ID type
                                                                                *
                                                                                * @return None
                                                                                *
                                                                                *******************************************************************************/
void TIMER_ClearIntStatus(TIMER_Chan_Type timerCh, TIMER_Comp_ID_Type cmpNo) {
  uint32_t tmpAddr;
  uint32_t tmpVal;

  /* Check the parameters */
  CHECK_PARAM(IS_TIMER_CHAN_TYPE(timerCh));
  CHECK_PARAM(IS_TIMER_COMP_ID_TYPE(cmpNo));

  tmpAddr = TIMER_BASE + TIMER_TICR2_OFFSET + 4 * timerCh;

  tmpVal = BL_RD_WORD(tmpAddr);
  tmpVal |= (1 << cmpNo);

  BL_WR_WORD(tmpAddr, tmpVal);
}

/****************************************************************************/ /**
                                                                                * @brief  TIMER initialization function
                                                                                *
                                                                                * @param  timerCfg: TIMER configuration structure pointer
                                                                                *
                                                                                * @return SUCCESS or ERROR
                                                                                *
                                                                                *******************************************************************************/
BL_Err_Type TIMER_Init(TIMER_CFG_Type *timerCfg) {
  TIMER_Chan_Type timerCh = timerCfg->timerCh;
  uint32_t        tmpVal;

  /* Check the parameters */
  CHECK_PARAM(IS_TIMER_CLKSRC_TYPE(timerCfg->clkSrc));
  CHECK_PARAM(IS_TIMER_CHAN_TYPE(timerCfg->timerCh));
  CHECK_PARAM(IS_TIMER_PRELOAD_TRIG_TYPE(timerCfg->plTrigSrc));
  CHECK_PARAM(IS_TIMER_COUNTMODE_TYPE(timerCfg->countMode));

  /* Configure timer clock source */
  tmpVal = BL_RD_REG(TIMER_BASE, TIMER_TCCR);

  if (timerCh == TIMER_CH0) {
    tmpVal = BL_SET_REG_BITS_VAL(tmpVal, TIMER_CS_1, timerCfg->clkSrc);
  } else {
    tmpVal = BL_SET_REG_BITS_VAL(tmpVal, TIMER_CS_2, timerCfg->clkSrc);
  }

  BL_WR_REG(TIMER_BASE, TIMER_TCCR, tmpVal);

  /* Configure timer clock division */
  tmpVal = BL_RD_REG(TIMER_BASE, TIMER_TCDR);

  if (timerCh == TIMER_CH0) {
    tmpVal = BL_SET_REG_BITS_VAL(tmpVal, TIMER_TCDR2, timerCfg->clockDivision);
  } else {
    tmpVal = BL_SET_REG_BITS_VAL(tmpVal, TIMER_TCDR3, timerCfg->clockDivision);
  }

  BL_WR_REG(TIMER_BASE, TIMER_TCDR, tmpVal);

  /* Configure timer count mode: preload or free run */
  TIMER_SetCountMode(timerCh, timerCfg->countMode);

  /* Configure timer preload trigger src */
  TIMER_SetPreloadTrigSrc(timerCh, timerCfg->plTrigSrc);

  if (timerCfg->countMode == TIMER_COUNT_PRELOAD) {
    /* Configure timer preload value */
    TIMER_SetPreloadValue(timerCh, timerCfg->preLoadVal);

    /* Configure match compare values */
    if (timerCfg->matchVal0 > 1 + timerCfg->preLoadVal) {
      TIMER_SetCompValue(timerCh, TIMER_COMP_ID_0, timerCfg->matchVal0 - 2);
    } else {
      TIMER_SetCompValue(timerCh, TIMER_COMP_ID_0, timerCfg->matchVal0);
    }

    if (timerCfg->matchVal1 > 1 + timerCfg->preLoadVal) {
      TIMER_SetCompValue(timerCh, TIMER_COMP_ID_1, timerCfg->matchVal1 - 2);
    } else {
      TIMER_SetCompValue(timerCh, TIMER_COMP_ID_1, timerCfg->matchVal1);
    }

    if (timerCfg->matchVal2 > 1 + timerCfg->preLoadVal) {
      TIMER_SetCompValue(timerCh, TIMER_COMP_ID_2, timerCfg->matchVal2 - 2);
    } else {
      TIMER_SetCompValue(timerCh, TIMER_COMP_ID_2, timerCfg->matchVal2);
    }
  } else {
    /* Configure match compare values */
    if (timerCfg->matchVal0 > 1) {
      TIMER_SetCompValue(timerCh, TIMER_COMP_ID_0, timerCfg->matchVal0 - 2);
    } else {
      TIMER_SetCompValue(timerCh, TIMER_COMP_ID_0, timerCfg->matchVal0);
    }

    if (timerCfg->matchVal1 > 1) {
      TIMER_SetCompValue(timerCh, TIMER_COMP_ID_1, timerCfg->matchVal1 - 2);
    } else {
      TIMER_SetCompValue(timerCh, TIMER_COMP_ID_1, timerCfg->matchVal1);
    }

    if (timerCfg->matchVal2 > 1) {
      TIMER_SetCompValue(timerCh, TIMER_COMP_ID_2, timerCfg->matchVal2 - 2);
    } else {
      TIMER_SetCompValue(timerCh, TIMER_COMP_ID_2, timerCfg->matchVal2);
    }
  }

#ifndef BFLB_USE_HAL_DRIVER
  Interrupt_Handler_Register(TIMER_CH0_IRQn, TIMER_CH0_IRQHandler);
  Interrupt_Handler_Register(TIMER_CH1_IRQn, TIMER_CH1_IRQHandler);
#endif

  return SUCCESS;
}

/****************************************************************************/ /**
                                                                                * @brief  TIMER enable one channel function
                                                                                *
                                                                                * @param  timerCh: TIMER channel type
                                                                                *
                                                                                * @return None
                                                                                *
                                                                                *******************************************************************************/
void TIMER_Enable(TIMER_Chan_Type timerCh) {
  uint32_t tmpVal;

  /* Check the parameters */
  CHECK_PARAM(IS_TIMER_CHAN_TYPE(timerCh));

  tmpVal = BL_RD_REG(TIMER_BASE, TIMER_TCER);
  tmpVal |= (1 << (timerCh + 1));

  BL_WR_REG(TIMER_BASE, TIMER_TCER, tmpVal);
}

/****************************************************************************/ /**
                                                                                * @brief  TIMER disable one channel function
                                                                                *
                                                                                * @param  timerCh: TIMER channel type
                                                                                *
                                                                                * @return None
                                                                                *
                                                                                *******************************************************************************/
void TIMER_Disable(TIMER_Chan_Type timerCh) {
  uint32_t tmpVal;

  /* Check the parameters */
  CHECK_PARAM(IS_TIMER_CHAN_TYPE(timerCh));

  tmpVal = BL_RD_REG(TIMER_BASE, TIMER_TCER);
  tmpVal &= (~(1 << (timerCh + 1)));

  BL_WR_REG(TIMER_BASE, TIMER_TCER, tmpVal);
}

/****************************************************************************/ /**
                                                                                * @brief  TIMER mask or unmask certain or all interrupt
                                                                                *
                                                                                * @param  timerCh: TIMER channel type
                                                                                * @param  intType: TIMER interrupt type
                                                                                * @param  intMask: TIMER interrupt mask value:MASK:disbale interrupt.UNMASK:enable interrupt
                                                                                *
                                                                                * @return None
                                                                                *
                                                                                *******************************************************************************/
void TIMER_IntMask(TIMER_Chan_Type timerCh, TIMER_INT_Type intType, BL_Mask_Type intMask) {
  uint32_t tmpAddr;
  uint32_t tmpVal;

  /* Check the parameters */
  CHECK_PARAM(IS_TIMER_CHAN_TYPE(timerCh));
  CHECK_PARAM(IS_TIMER_INT_TYPE(intType));
  CHECK_PARAM(IS_BL_MASK_TYPE(intMask));

  tmpAddr = TIMER_BASE + TIMER_TIER2_OFFSET + 4 * timerCh;
  tmpVal  = BL_RD_WORD(tmpAddr);

  switch (intType) {
  case TIMER_INT_COMP_0:
    if (intMask == UNMASK) {
      /* Enable this interrupt */
      BL_WR_WORD(tmpAddr, BL_SET_REG_BIT(tmpVal, TIMER_TIER_0));
    } else {
      /* Disable this interrupt */
      BL_WR_WORD(tmpAddr, BL_CLR_REG_BIT(tmpVal, TIMER_TIER_0));
    }

    break;

  case TIMER_INT_COMP_1:
    if (intMask == UNMASK) {
      /* Enable this interrupt */
      BL_WR_WORD(tmpAddr, BL_SET_REG_BIT(tmpVal, TIMER_TIER_1));
    } else {
      /* Disable this interrupt */
      BL_WR_WORD(tmpAddr, BL_CLR_REG_BIT(tmpVal, TIMER_TIER_1));
    }

    break;

  case TIMER_INT_COMP_2:
    if (intMask == UNMASK) {
      /* Enable this interrupt */
      BL_WR_WORD(tmpAddr, BL_SET_REG_BIT(tmpVal, TIMER_TIER_2));
    } else {
      /* Disable this interrupt */
      BL_WR_WORD(tmpAddr, BL_CLR_REG_BIT(tmpVal, TIMER_TIER_2));
    }

    break;

  case TIMER_INT_ALL:
    if (intMask == UNMASK) {
      /* Enable this interrupt */
      BL_WR_WORD(tmpAddr, BL_SET_REG_BIT(tmpVal, TIMER_TIER_0));
      BL_WR_WORD(tmpAddr, BL_SET_REG_BIT(tmpVal, TIMER_TIER_1));
      BL_WR_WORD(tmpAddr, BL_SET_REG_BIT(tmpVal, TIMER_TIER_2));
    } else {
      /* Disable this interrupt */
      BL_WR_WORD(tmpAddr, BL_CLR_REG_BIT(tmpVal, TIMER_TIER_0));
      BL_WR_WORD(tmpAddr, BL_CLR_REG_BIT(tmpVal, TIMER_TIER_1));
      BL_WR_WORD(tmpAddr, BL_CLR_REG_BIT(tmpVal, TIMER_TIER_2));
    }

    break;

  default:
    break;
  }
}

/****************************************************************************/ /**
                                                                                * @brief  TIMER set watchdog clock source and clock division
                                                                                *
                                                                                * @param  clkSrc: Watchdog timer clock source type
                                                                                * @param  div: Watchdog timer clock division value
                                                                                *
                                                                                * @return None
                                                                                *
                                                                                *******************************************************************************/
void WDT_Set_Clock(TIMER_ClkSrc_Type clkSrc, uint8_t div) {
  uint32_t tmpVal;

  /* Check the parameters */
  CHECK_PARAM(IS_TIMER_CLKSRC_TYPE(clkSrc));

  /* Configure watchdog timer clock source */
  tmpVal = BL_RD_REG(TIMER_BASE, TIMER_TCCR);
  tmpVal = BL_SET_REG_BITS_VAL(tmpVal, TIMER_CS_WDT, clkSrc);
  BL_WR_REG(TIMER_BASE, TIMER_TCCR, tmpVal);

  /* Configure watchdog timer clock divison */
  tmpVal = BL_RD_REG(TIMER_BASE, TIMER_TCDR);
  tmpVal = BL_SET_REG_BITS_VAL(tmpVal, TIMER_WCDR, div);
  BL_WR_REG(TIMER_BASE, TIMER_TCDR, tmpVal);
}

/****************************************************************************/ /**
                                                                                * @brief  TIMER get watchdog match compare value
                                                                                *
                                                                                * @param  None
                                                                                *
                                                                                * @return Watchdog match comapre register value
                                                                                *
                                                                                *******************************************************************************/
uint16_t WDT_GetMatchValue(void) {
  uint32_t tmpVal;

  WDT_ENABLE_ACCESS();

  /* Get watchdog timer match register value */
  tmpVal = BL_RD_REG(TIMER_BASE, TIMER_WMR);

  return tmpVal;
}

/****************************************************************************/ /**
                                                                                * @brief  TIMER set watchdog match compare value
                                                                                *
                                                                                * @param  val: Watchdog match compare value
                                                                                *
                                                                                * @return None
                                                                                *
                                                                                *******************************************************************************/
void WDT_SetCompValue(uint16_t val) {
  WDT_ENABLE_ACCESS();

  /* Set watchdog timer match register value */
  BL_WR_REG(TIMER_BASE, TIMER_WMR, val);
}

/****************************************************************************/ /**
                                                                                * @brief  TIMER get watchdog count register value
                                                                                *
                                                                                * @param  None
                                                                                *
                                                                                * @return Watchdog count register value
                                                                                *
                                                                                *******************************************************************************/
uint16_t WDT_GetCounterValue(void) {
  uint32_t tmpVal;

  WDT_ENABLE_ACCESS();

  /* Get watchdog timer count register value */
  tmpVal = BL_RD_REG(TIMER_BASE, TIMER_WVR);

  return tmpVal;
}

/****************************************************************************/ /**
                                                                                * @brief  TIMER reset watchdog count register value
                                                                                *
                                                                                * @param  None
                                                                                *
                                                                                * @return None
                                                                                *
                                                                                *******************************************************************************/
void WDT_ResetCounterValue(void) {
  uint32_t tmpVal;

  /* Reset watchdog timer count register value */
  WDT_ENABLE_ACCESS();

  tmpVal = BL_RD_REG(TIMER_BASE, TIMER_WCR);

  /* Set watchdog counter reset register bit0 to 1 */
  BL_WR_REG(TIMER_BASE, TIMER_WCR, BL_SET_REG_BIT(tmpVal, TIMER_WCR));
}

/****************************************************************************/ /**
                                                                                * @brief  TIMER get watchdog reset status
                                                                                *
                                                                                * @param  None
                                                                                *
                                                                                * @return SET or RESET
                                                                                *
                                                                                *******************************************************************************/
BL_Sts_Type WDT_GetResetStatus(void) {
  uint32_t tmpVal;

  WDT_ENABLE_ACCESS();

  /* Get watchdog status register */
  tmpVal = BL_RD_REG(TIMER_BASE, TIMER_WSR);

  return (BL_IS_REG_BIT_SET(tmpVal, TIMER_WTS)) ? SET : RESET;
}

/****************************************************************************/ /**
                                                                                * @brief  TIMER clear watchdog reset status
                                                                                *
                                                                                * @param  None
                                                                                *
                                                                                * @return None
                                                                                *
                                                                                *******************************************************************************/
void WDT_ClearResetStatus(void) {
  uint32_t tmpVal;

  WDT_ENABLE_ACCESS();

  tmpVal = BL_RD_REG(TIMER_BASE, TIMER_WSR);

  /* Set watchdog status register */
  BL_WR_REG(TIMER_BASE, TIMER_WSR, BL_CLR_REG_BIT(tmpVal, TIMER_WTS));
}

/****************************************************************************/ /**
                                                                                * @brief  TIMER enable watchdog function
                                                                                *
                                                                                * @param  None
                                                                                *
                                                                                * @return None
                                                                                *
                                                                                *******************************************************************************/
void WDT_Enable(void) {
  uint32_t tmpVal;

#ifndef BFLB_USE_HAL_DRIVER
  Interrupt_Handler_Register(TIMER_WDT_IRQn, TIMER_WDT_IRQHandler);
#endif

  WDT_ENABLE_ACCESS();

  tmpVal = BL_RD_REG(TIMER_BASE, TIMER_WMER);

  BL_WR_REG(TIMER_BASE, TIMER_WMER, BL_SET_REG_BIT(tmpVal, TIMER_WE));
}

/****************************************************************************/ /**
                                                                                * @brief  Watchdog timer disable function
                                                                                *
                                                                                * @param  None
                                                                                *
                                                                                * @return None
                                                                                *
                                                                                *******************************************************************************/
void WDT_Disable(void) {
  uint32_t tmpVal;

  WDT_ENABLE_ACCESS();

  tmpVal = BL_RD_REG(TIMER_BASE, TIMER_WMER);

  BL_WR_REG(TIMER_BASE, TIMER_WMER, BL_CLR_REG_BIT(tmpVal, TIMER_WE));
}

/****************************************************************************/ /**
                                                                                * @brief  Watchdog timer mask or unmask certain or all interrupt
                                                                                *
                                                                                * @param  intType: Watchdog interrupt type
                                                                                * @param  intMask: Watchdog interrupt mask value:MASK:disbale interrupt.UNMASK:enable interrupt
                                                                                *
                                                                                * @return None
                                                                                *
                                                                                *******************************************************************************/
void WDT_IntMask(WDT_INT_Type intType, BL_Mask_Type intMask) {
  uint32_t tmpVal;

  /* Check the parameters */
  CHECK_PARAM(IS_WDT_INT_TYPE(intType));
  CHECK_PARAM(IS_BL_MASK_TYPE(intMask));

  WDT_ENABLE_ACCESS();

  /* Deal with watchdog match/interrupt enable register,
    WRIE:watchdog reset/interrupt enable */
  tmpVal = BL_RD_REG(TIMER_BASE, TIMER_WMER);

  switch (intType) {
  case WDT_INT:
    if (intMask == UNMASK) {
      /* Enable this interrupt */
      /* 0 means generates a watchdog interrupt,
         a watchdog timer reset is not generated*/
      BL_WR_REG(TIMER_BASE, TIMER_WMER, BL_CLR_REG_BIT(tmpVal, TIMER_WRIE));
    } else {
      /* Disable this interrupt */
      /* 1 means generates a watchdog timer reset,
         a watchdog  interrupt is not generated*/
      BL_WR_REG(TIMER_BASE, TIMER_WMER, BL_SET_REG_BIT(tmpVal, TIMER_WRIE));
    }

    break;

  default:
    break;
  }
}

/****************************************************************************/ /**
                                                                                * @brief  TIMER channel 0 interrupt handler
                                                                                *
                                                                                * @param  None
                                                                                *
                                                                                * @return None
                                                                                *
                                                                                *******************************************************************************/
#ifndef BFLB_USE_HAL_DRIVER
void TIMER_CH0_IRQHandler(void) { TIMER_IntHandler(TIMER_CH0_IRQn, TIMER_CH0); }
#endif

/****************************************************************************/ /**
                                                                                * @brief  TIMER channel 1 interrupt handler
                                                                                *
                                                                                * @param  None
                                                                                *
                                                                                * @return None
                                                                                *
                                                                                *******************************************************************************/
#ifndef BFLB_USE_HAL_DRIVER
void TIMER_CH1_IRQHandler(void) { TIMER_IntHandler(TIMER_CH1_IRQn, TIMER_CH1); }
#endif

/****************************************************************************/ /**
                                                                                * @brief  TIMER watchdog interrupt handler
                                                                                *
                                                                                * @param  None
                                                                                *
                                                                                * @return None
                                                                                *
                                                                                *******************************************************************************/
#ifndef BFLB_USE_HAL_DRIVER
void TIMER_WDT_IRQHandler(void) {
  uint32_t tmpVal;

  WDT_ENABLE_ACCESS();

  tmpVal = BL_RD_REG(TIMER_BASE, TIMER_WICR);
  BL_WR_REG(TIMER_BASE, TIMER_WICR, BL_SET_REG_BIT(tmpVal, TIMER_WICLR));

  if (timerIntCbfArra[TIMER_WDT_IRQn - TIMER_CH0_IRQn][WDT_INT] != NULL) {
    /* Call the callback function */
    timerIntCbfArra[TIMER_WDT_IRQn - TIMER_CH0_IRQn][WDT_INT]();
  }
}
#endif

/****************************************************************************/ /**
                                                                                * @brief  TIMER install interrupt callback
                                                                                *
                                                                                * @param  timerChan: TIMER channel type
                                                                                * @param  intType: TIMER interrupt type
                                                                                * @param  cbFun: Pointer to interrupt callback function. The type should be void (*fn)(void)
                                                                                *
                                                                                * @return None
                                                                                *
                                                                                *******************************************************************************/
void Timer_Int_Callback_Install(TIMER_Chan_Type timerChan, TIMER_INT_Type intType, intCallback_Type *cbFun) {
  /* Check the parameters */
  CHECK_PARAM(IS_TIMER_CHAN_TYPE(timerChan));
  CHECK_PARAM(IS_TIMER_INT_TYPE(intType));

  timerIntCbfArra[timerChan][intType] = cbFun;
}

/****************************************************************************/ /**
                                                                                * @brief  Watchdog install interrupt callback
                                                                                *
                                                                                * @param  wdtInt: Watchdog interrupt type
                                                                                * @param  cbFun: Pointer to interrupt callback function. The type should be void (*fn)(void)
                                                                                *
                                                                                * @return None
                                                                                *
                                                                                *******************************************************************************/
void WDT_Int_Callback_Install(WDT_INT_Type wdtInt, intCallback_Type *cbFun) {
  /* Check the parameters */
  CHECK_PARAM(IS_WDT_INT_TYPE(wdtInt));

  timerIntCbfArra[2][wdtInt] = cbFun;
}

/*@} end of group TIMER_Private_Functions */

/*@} end of group TIMER */

/*@} end of group BL702_Peripheral_Driver */
